package org.roguelikedevelopment.dweller.j2se;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.Rectangle2D;

import org.roguelikedevelopment.dweller.common.application.DwellerCanvas;
import org.roguelikedevelopment.dweller.common.game.GameCommand;
import org.roguelikedevelopment.dweller.common.game.GameHandler;
import org.roguelikedevelopment.dweller.common.ui.GameUI;
import org.roguelikedevelopment.dweller.common.ui.MenuUI;
import org.roguelikedevelopment.dweller.common.util.Direction;
import org.roguelikedevelopment.dweller.common.util.Position;
import org.roguelikedevelopment.dweller.common.util.logger.Logger;

public class DwellerJ2SECanvas extends Canvas implements DwellerCanvas, KeyListener, MouseListener, MouseMotionListener, MouseWheelListener, ComponentListener {

	private static final long serialVersionUID = 1L;

	/** Pixel position of the last pointer pressed event */
	private Position pointerPressed = new Position(0, 0);

	/** Pixel position of the last pointer released event */
	private Position pointerReleased = new Position(0, 0);

	/** Pixel position of the last pointer released event */
	private Position pointerDragged = new Position(0, 0);
	
	/** Time when the last pointer pressed was received */
	private long pointerPressedTimestamp;
	
	private boolean dragging = false;
	
	public int CHARACTER_OFFSETY = 0;
	public int characterWidth;
	public int characterHeight;
	public int charactersPerRow;
	public int charactersPerColumn;
	
	private GameHandler game;
	
	private Font font;
	private FontMetrics fontMetrics;
	
	private DwellerJ2SEGraphics graphics;

	public DwellerJ2SECanvas(int width, int height, GameHandler game) {
		super();
		this.game = game;
		
		font = new Font(Font.SANS_SERIF, Font.PLAIN, 12);
		setFont(font);
		setBackground(Color.BLACK);

		setSize(width, height);
		setVisible(true);
		addKeyListener(this);
		addMouseListener(this);
		addMouseWheelListener(this);
		addMouseMotionListener(this);
		addComponentListener(this);

		graphics = new DwellerJ2SEGraphics(this);
	}
	
	public void initialize() {
		Graphics g = getGraphics();
		fontMetrics = g.getFontMetrics();
		characterHeight = fontMetrics.getHeight();
		characterWidth = fontMetrics.charWidth('@');
		charactersPerRow = getWidth() / characterWidth;
		charactersPerColumn = getHeight() / characterHeight;
		MenuUI.setPageHeight(charactersPerColumn);
	}
	
	
	public void loadGraphics() {
		graphics.loadGraphics();
	}
	
	public void loadASCII() {
		graphics.loadASCII();
	}
	
	public void useNormalTiles() {
		graphics.useNormalTiles();
	}
	
	public void useLargeTiles() {
		graphics.useLargeTiles();
	}
	
	@Override
	public int getCharacterHeight() {
		return characterHeight;
	}

	@Override
	public int getCharactersPerColumn() {
		return charactersPerColumn;
	}

	@Override
	public int getCharactersPerRow() {
		return charactersPerRow;
	}

	@Override
	public int getTileHeight() {
		return graphics.getTileHeight();
	}

	@Override
	public int getTileWidth() {
		return graphics.getTileWidth();
	}

	@Override
	public int getTilesPerColumn() {
		return graphics.getTilesPerColumn();
	}

	@Override
	public int getTilesPerRow() {
		return graphics.getTilesPerRow();
	}

	@Override
	public boolean isTouchEnabled() {
		return true;
	}
	
	public void update(Graphics g) {
		paint(g);
	}	
	
	public void paint(Graphics g) {
		Graphics2D g2d = (Graphics2D)g;
		graphics.setGraphics(g2d);
		game.render(graphics);
	}

	@Override
	public int stringWidth(String str) {
		Graphics g = getGraphics();
		Rectangle2D r2d = fontMetrics.getStringBounds(str, g);
		Rectangle r = r2d.getBounds();
		return r.width;
	}

	@Override
	public int substringWidth(String str, int offset, int len) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public void keyPressed(KeyEvent e) {
		System.out.println("keyPressed() " + e.getKeyCode());
		game.keyPress(e.getKeyCode());
		repaint();
	}

	@Override
	public void keyReleased(KeyEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void keyTyped(KeyEvent e) {
		// TODO Auto-generated method stub		
	}

	@Override
	public void mouseClicked(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseExited(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mousePressed(MouseEvent e) {
		pointerPressedTimestamp = System.currentTimeMillis();
		pointerPressed.x = e.getX();
		pointerPressed.y = e.getY();
		pointerDragged.x = e.getX();
		pointerDragged.y = e.getY();
		game.pointerPressed(new Position(e.getX(), e.getY()));
		repaint();
	}

	@Override
	public void mouseReleased(MouseEvent e) {
		if(dragging) {
			dragging = false;
			return;
		}
		pointerReleased.x = e.getX();
		pointerReleased.y = e.getY();
		game.pointerReleased(pointerReleased, System.currentTimeMillis() - pointerPressedTimestamp);
		repaint();
	}

	@Override
	public void mouseDragged(MouseEvent e) {
		dragging = true;
		int ydist = pointerDragged.y - e.getY();
		int xdist = pointerDragged.x - e.getX();
		
		if(Math.abs(ydist) < getCharacterHeight() && Math.abs(xdist) < getCharacterHeight()) {
			return;
		}
		
		game.pointerDragged(Direction.direction(pointerDragged.x, pointerDragged.y, e.getX(), e.getY()));

		pointerDragged.x = e.getX();
		pointerDragged.y = e.getY();
		repaint();
	}

	@Override
	public void mouseMoved(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseWheelMoved(MouseWheelEvent e) {
		if(e.getWheelRotation() < 0) {
			game.keyPress(GameCommand.CMD_UP.getKeyCode());
			repaint();
		}
		else if(e.getWheelRotation() > 0) {
			game.keyPress(GameCommand.CMD_DOWN.getKeyCode());
			repaint();
		}
	}
	
	public void sizeChanged() {
		Logger.debug("w = " + getWidth() + " h = " + getHeight());
	}

	@Override
	public void componentHidden(ComponentEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void componentMoved(ComponentEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void componentResized(ComponentEvent e) {
		initialize();
		graphics.updateSize();
		GameUI ui = game.getCurrentUI();
		if(ui != null) {
			ui.updateSize();
		}
		repaint();
	}

	@Override
	public void componentShown(ComponentEvent e) {
		// TODO Auto-generated method stub
		
	}
}
